#include "config.h"

#include <sys/types.h>
#include <regex.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <sys/vfs.h>
#include <unistd.h>
#include <getopt.h>
#include <dirent.h>
#include <sys/statvfs.h>

#define DBG_SUBSYS S_LIBCLUSTER

#include "sysy_lib.h"
#include "metadata.h"
#include "configure.h"
#include "bmap.h"
#include "node.h"
#include "nodetable.h"
#include "net_global.h"
#include "nodeid.h"
#include "net_table.h"
#include "ylog.h"
#include "dbg.h"
#include "bh.h"

//node id for 1 to 32768, avoid 0

typedef struct {
        bmap_t bmap;
} nodeid_t;

static nodeid_t *__nodeid__ = NULL;

int nodeid_init()
{
        int ret;
        nodeid_t *nodeid;

        ret = ymalloc((void **)&nodeid, sizeof(nodeid_t));
        if (unlikely(ret))
                GOTO(err_ret, ret);

        ret = bmap_create(&nodeid->bmap, INT16_MAX);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        __nodeid__ = nodeid;

        return 0;
err_ret:
        return ret;
}

static int __nodeid_newid(const char *key, const char *name)
{
        int ret, retry = 0;

retry:
        ret = etcd_create_text(ETCD_NID, key, name, 0);
        if (unlikely(ret)) {
                if (ret == EAGAIN) {
                        USLEEP_RETRY(err_ret, ret, retry, retry, 10, (100 * 1000));
                } else {
                        GOTO(err_ret, ret);
                }
        }
        
        return 0;
err_ret:
        return ret;
}

int nodeid_newid(int16_t *_id, const char *name)
{
        int ret, id;
        char key[MAX_PATH_LEN];

        if (__nodeid__ == NULL) {
                ret = EAGAIN;
                GOTO(err_ret, ret);
        }

        int retry = 0;
retry:
        id = bmap_get_empty(&__nodeid__->bmap);
        if (id == -1) {
                ret = ENOSPC;
                GOTO(err_ret, ret);
        }

        ret = bmap_set(&__nodeid__->bmap, id);
        if (unlikely(ret))
                UNIMPLEMENTED(__DUMP__);

        *_id = (id + 1);
        snprintf(key, MAX_NAME_LEN, "%d", *_id);

        ret = __nodeid_newid(key, name);
        if (unlikely(ret)) {
                if (ret == EEXIST) {
                        DERROR("skip key %s name %s ret %d\n", key, name, ret);
                        USLEEP_RETRY(err_ret, ret, retry, retry, 10, (10 * 1000));
                } else {
                        GOTO(err_ret, ret);
                }
        }
        
        return 0;
err_ret:
        return ret;
}

int nodeid_drop(int16_t id)
{
        int ret;
        char key[MAX_PATH_LEN];

        ret = bmap_del(&__nodeid__->bmap, id - 1);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        snprintf(key, MAX_NAME_LEN, "%d", id);
        ret = etcd_del(ETCD_NID, key);
        if (unlikely(ret)) {
                UNIMPLEMENTED(__DUMP__);
        }
        
        return 0;
err_ret:
        return ret;
}


int nodeid_used(int16_t id)
{
        return bmap_set(&__nodeid__->bmap, id - 1);
}

void nodeid_destroy()
{
        bmap_destroy(&__nodeid__->bmap);
        yfree((void **)&__nodeid__);
}
